﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;

namespace NetScraperLibrary
{
    public class ScrapedPage
    {
        #region Data Members

        private string _uri;
        private string _source;
        private List<string> _links;
        private DataSet _tables;
        private bool _error;
        private string _errorMessage;

        #endregion

        #region Properties

        public string Source
        {
            get { return _source; }
            set { _source = value; }
        }

        public List<string> Links
        {
            get { return _links; }
            set { _links = value; }
        }

        public DataSet Tables
        {
            get { return _tables; }
            set { _tables = value; }
        }

        public bool Error
        {
            get { return _error; }
            set { _error = value; }
        }

        public string ErrorMessage
        {
            get { return _errorMessage; }
            set { _errorMessage = value; }
        }

        #endregion

        #region Constructors

        public ScrapedPage()
        {
        }

        public ScrapedPage(string uri, string sourceContent)
        {
            _uri = uri;
            _source = sourceContent;
            _links = ParseLinks(sourceContent);
            _tables = ParseTables(sourceContent);
        }

        #endregion

        #region Methods

        public List<string> ParseLinks(string source)
        {
            List<string> links = new List<string>();

            try
            {
                Regex search = new Regex("href\\s*=\\s*(?:(?:\\\"(?<url>[^\\\"]*)\\\")|(?<url>[^\\s]* ))");
                MatchCollection matches = search.Matches(source);

                foreach (Match match in matches)
                {
                    links.Add(match.Groups["url"].Value);
                }
            }
            catch (Exception ex)
            {
                _error = true;
                _errorMessage += "Error parsing page links.\n";
            }

            return links;
        }

        public DataSet ParseTables(string source)
        {
            DataTable dt;
            DataSet ds = new DataSet();

            string tableRegex = "<table[^>]*>(.*?)</table>";
            string headerRegex = "<th[^>]*>(.*?)</th>";
            string rowRegex = "<tr[^>]*>(.*?)</tr>";
            string columnRegex = "<td[^>]*>(.*?)</td>";

            RegexOptions options = 
                RegexOptions.Singleline | 
                RegexOptions.Multiline | 
                RegexOptions.IgnoreCase;

            bool headersExist = false;
            int currentColumn = 0;
            int currentRow = 0;

            MatchCollection tables = Regex.Matches(
                source,
                tableRegex,
                RegexOptions.Singleline |
                RegexOptions.Multiline |
                RegexOptions.IgnoreCase
                );


            foreach (Match table in tables)
            {
                currentRow = 0;
                headersExist = false;
                dt = new DataTable();

                if (table.Value.Contains("<th"))
                {
                    headersExist = true;

                    MatchCollection headers = Regex.Matches(
                        table.Value,
                        headerRegex,
                        options
                        );

                    foreach (Match header in headers)
                    {
                        dt.Columns.Add(header.Groups[1].ToString());
                    }
                }
                else
                {
                    int columnCount = Regex.Matches(
                        Regex.Matches(
                            Regex.Matches(
                                table.Value,
                                tableRegex,
                                options)[0].ToString(),
                            rowRegex, 
                            options)[0].ToString(),
                        columnRegex,
                        options).Count;

                    for (int columns = 1; columns <= columnCount; columns++)
                    {
                        dt.Columns.Add("Column " + columns.ToString());
                    }
                }

                MatchCollection rows = Regex.Matches(
                    table.Value,
                    rowRegex,
                    options
                    );

                foreach (Match row in rows)
                {
                    if (!((currentRow == 0) & headersExist))
                    {
                        DataRow dr = dt.NewRow();
                        currentColumn = 0;

                        MatchCollection columns = Regex.Matches(
                            row.Value,
                            columnRegex,
                            options);

                        foreach (Match column in columns)
                        {
                            dr[currentColumn] = column.Groups[1].ToString();
                            currentColumn++;
                        }

                        dt.Rows.Add(dr);
                    }

                    currentRow++;
                }

                ds.Tables.Add(dt);
            }

            return ds;
        }

        #endregion

        #region Garbage Collection

        #endregion
    }
}
